Imports System.Xml
Imports System.Net

Public Class UserList

	Private list As Hashtable = New Hashtable()

	'====================================================================
	' Operations for all users: connect, disconnect, broadcast a message
	'====================================================================

#Region " Connect, Disconnect, SendText "

	Public Sub Connect()
		Dim u As RemoteUser
		For Each u In list.Values
			u.ConnectInitiate(LocalUserName, LocalUserAddress)
		Next
	End Sub

	Public Sub Disconnect()
		Dim u As RemoteUser
		For Each u In list.Values
			u.Disconnect()
		Next
	End Sub

	'====================================================================

	Public Sub SendText(ByVal Text As String)
		Dim u As RemoteUser
		For Each u In list.Values
			u.SendText(Text)
		Next
	End Sub

	Public Sub SendStatus(ByVal NewStatus As UserStatus)
		If NewStatus = UserStatus.Offline Then Return ' Cannot be offline when sending.

		Dim u As RemoteUser
		For Each u In list.Values
			u.SendStatus(NewStatus)
		Next
	End Sub

#End Region

	'====================================================================

#Region " Events "

	'====================================================================
	' Events
	'====================================================================

	Public Event UserConnected(ByVal Sender As RemoteUser)
	Public Event UserDisconnected(ByVal Sender As RemoteUser)
	Public Event UserReceivedText(ByVal Sender As RemoteUser, ByVal Text As String)
	Public Event UserStatusChanged(ByVal Sender As RemoteUser)

	Private Sub OnUserConnected(ByVal Sender As Agent.RemoteUser)
		RaiseEvent UserConnected(Sender)
	End Sub

	Private Sub OnUserDisconnected(ByVal Sender As Agent.RemoteUser)
		RaiseEvent UserDisconnected(Sender)
	End Sub

	Private Sub OnUserReceivedText(ByVal Sender As Agent.RemoteUser, ByVal Text As String)
		RaiseEvent UserReceivedText(Sender, Text)
	End Sub

	Private Sub OnUserStatusChanged(ByVal Sender As Agent.RemoteUser)
		RaiseEvent UserStatusChanged(Sender)
	End Sub

#End Region

	'====================================================================
	' High-level List management (Load, Save, Modify)
	'====================================================================

#Region " This list's Properties: LocalUserName, LocalUserAddress, FileName "

	Private mLocalUserAddress As String
	Protected Property LocalUserAddress() As String
		Get
			Return mLocalUserAddress
		End Get
		Set(ByVal Value As String)
			mLocalUserAddress = Value
		End Set
	End Property

	Private mLocalUserName As String
	Public Property LocalUserName() As String
		Get
			Return mLocalUserName
		End Get
		Set(ByVal Value As String)
			mLocalUserName = Value
		End Set
	End Property

	Private mFileName As String = "ChatSettings.xml"
	Public Property FileName() As String
		Get
			Return mFileName
		End Get
		Set(ByVal Value As String)
			mFileName = Value
		End Set
	End Property

#End Region

#Region " Load from XML "

	Public Sub Load()
		Try
			Dim Doc As XmlDocument = New XmlDocument()
			Doc.Load(FileName)

			Dim Node1 As XmlNode = Doc.SelectSingleNode("/Chat/LocalUser")
			LocalUserName = Node1("Name").InnerText
			LocalUserAddress = Node1("Address").InnerText

			Dim Nodes As XmlNodeList = Doc.GetElementsByTagName("User")

			For Each Node1 In Nodes
				Dim NewName As String = Node1("Name").InnerText
				Dim NewAddress As String = Node1("Address").InnerText
				Dim NewUser As RemoteUser = AddRemoteUser(NewName, NewAddress)
			Next

		Catch e As System.IO.FileNotFoundException
		Finally
			If LocalUserName = "" Then LocalUserName = SystemInformation.UserName
			If LocalUserAddress = "" Then LocalUserAddress = SystemInformation.ComputerName
		End Try
	End Sub

#End Region

#Region " Save to XML "

	Public Sub Save()
		Dim Writer As XmlTextWriter
		Dim File As System.IO.StreamWriter

		Try
			File = New IO.StreamWriter(FileName, False, System.Text.Encoding.Unicode)
			Writer = New XmlTextWriter(File)
			Writer.Formatting = Formatting.Indented

			'====================================================================
			Writer.WriteStartDocument()
			Writer.WriteStartElement("Chat")

			Writer.WriteStartElement("LocalUser")
			Writer.WriteElementString("Name", LocalUserName)
			Writer.WriteElementString("Address", LocalUserAddress)
			Writer.WriteEndElement()

			Writer.WriteStartElement("Users")
			Dim User As RemoteUser
			For Each User In list.Values
				Writer.WriteStartElement("User")
				Writer.WriteElementString("Name", User.Name)
				Writer.WriteElementString("Address", User.Address)
				Writer.WriteEndElement()
			Next
			Writer.WriteEndElement()

			Writer.WriteEndElement()
			Writer.WriteEndDocument()
			'====================================================================

		Finally
			If Not Writer Is Nothing Then
				Writer.Close()
			End If
		End Try
	End Sub

#End Region

	'====================================================================
	' Add user
	'====================================================================

#Region " Add users to the list "

	' called to add a user who contacted us with an invitation.
	Public Sub AddUserIncomingRequest(ByVal Name As String, ByVal Address As String, ByVal ExistingConnection As UserConnection)
		Dim NewUser As RemoteUser = AddRemoteUser(Name, Address)
		NewUser.ConnectRespond(ExistingConnection)
		Save()
	End Sub

	' called to add a user whom we contacted.
	Public Sub AddUserOutgoingRequest(ByVal Name As String, ByVal Address As String)
		Dim NewUser As RemoteUser = AddRemoteUser(Name, Address)
		NewUser.ConnectInitiate(LocalUserName, LocalUserAddress)
		Save()
	End Sub

	'====================================================================

	Private Function AddRemoteUser(ByVal Name As String, ByVal Address As String) As RemoteUser
		Dim NewUser As RemoteUser = New RemoteUser(Name, Address)

		' map user's events to this list's events
		AddHandler NewUser.Connected, AddressOf Me.OnUserConnected
		AddHandler NewUser.Disconnected, AddressOf Me.OnUserDisconnected
		AddHandler NewUser.ReceivedText, AddressOf Me.OnUserReceivedText
		AddHandler NewUser.StatusChanged, AddressOf Me.OnUserStatusChanged

		Add(NewUser)
		Return NewUser
	End Function

	'====================================================================

	Protected Sub Add(ByVal NewUser As RemoteUser)
		list.Add(NewUser.Name, NewUser)
	End Sub

#End Region

	'====================================================================
	' Current user statistics.
	' Count
	' OnlineUsersCount
	' AnyUsersOnline
	' AllUsersNotAvailable
	'====================================================================

#Region " Current user statistics "

	Public ReadOnly Property Count() As Integer
		Get
			Return list.Count
		End Get
	End Property

	Public Function OnlineUsersCount() As Integer
		Dim u As RemoteUser
		Dim i As Integer = 0

		For Each u In list.Values
			If u.IsOnline Then i += 1
		Next

		Return i
	End Function

	Public Function AnyUsersOnline() As Boolean
		Return OnlineUsersCount() > 0
	End Function

	Public Function AllUsersNotAvailable() As Boolean
		Dim u As RemoteUser
		For Each u In list.Values
			If u.Status = UserStatus.Online Then Return False
		Next
		Return True
	End Function

#End Region

	'====================================================================
	' List operations:
	' Item(String Name)
	' GetEnumerator
	'====================================================================

#Region " List operations "

	' Return user object by name
	Default Public ReadOnly Property Item(ByVal Name As String) As RemoteUser
		Get
			Return DirectCast(list.Item(Name), RemoteUser)
		End Get
	End Property

	Public Function GetEnumerator() As System.Collections.IEnumerator
		Return list.Values.GetEnumerator()
	End Function

#End Region

End Class